返回包含 HTML 和 JavaScript 的 PartialView (Returning a PartialView with both HTML and JavaScript)


問題描述

返回包含 HTML 和 JavaScript 的 PartialView (Returning a PartialView with both HTML and JavaScript)

I am making an AJAX call (with jQuery) to retrieve a PartialView. Along with the HTML I'd like to send back a JSON representation of the object the View is displaying. The crappy way that I've been using is embedding properties as hidden inputs in the HTML, which quickly becomes unwieldy and tightly couples far too much stuff.

I could just send the JavaScript in a <script> tag after the HTML, but I'm really anal about keeping those things separate. That would look like this:

<%@ Control Language="C#" AutoEventWireup="true" Inherits="System.Web.Mvc.ViewUserControl<Person>" %>
<div class="person">
  First Name: <%= Html.TextBox("FirstName", Model.FirstName) %>
  Last Name: <%= Html.TextBox("LastName", Model.LastName) %>
</div>
<script type="text/javascript">
  // JsonSerialized object goes here
</script>

Another option I considered is to make a second AJAX call to an action that returns JsonResult, but that also feels like bad design.

‑‑‑‑‑

參考解法

方法 1:

I think I found a pretty good way to do this, just wrap the JSON up in an HtmlHelper extension. Here's the class:

using System.Web.Script.Serialization;

public static class JsonExtensions {
    public static string Json(this HtmlHelper html, string variableName) {
        return Json(html, variableName, html.ViewData.Model);
    }

    public static string Json(this HtmlHelper html, string variableName, object model) {
        TagBuilder tag = new TagBuilder("script");
        tag.Attributes.Add("type", "text/javascript");
        JavaScriptSerializer jsonSerializer = new JavaScriptSerializer();
        tag.InnerHtml = "var " + variableName + " = " + jsonSerializer.Serialize(model) + ";";
        return tag.ToString();
    }
}

And you call it via:

<%= Html.Json("foo") %>
<%= Html.Json("bar", Model.Something) %>

The one catch that I can think of is that it isn't a completely perfect separation; you are still technically putting JavaScript in the HTML. But, it doesn't make an extra call to the server, and the markup in the IDE is still very clean.

方法 2:

Probably not the most elegant answer you'll get, but just to throw this out there:

You could return purely json from your action method,

something that would look like this:

{
    Html: "<div class=\"person\"> etc...",
    Json: { // your object here
          }
}

in your controller you'll need something like this to render your view:

var existingContext = HttpContext.Current;
var writer = new StringWriter();
var response = new HttpResponse(writer);
var httpContext = new HttpContext(existingContext.Request, response);

var viewResult = myAction(bla);

HttpContext.Current = httpContext;

viewResult.ExecuteResult(this.ControllerContext)

HttpContext.Current = existingContext;
var viewAsHtml = writer.ToString();

方法 3:

The same solution as Andrew, but maybe a bit more MVC'ish...

Create a new class which inherits from ViewPage. Override its Render method to render the page itself, and then stuff that into the output Andrew suggested. So that all the hacking occurs in the Render method, where it should happen.

Now each view that you create you change the line:

<%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage<MyModel>" %>

with

<%@ Page Title="" Language="C#" Inherits="CustomViewPage<MyModel>" %>

I didn't check it myself, but guess it should work. If you want I can try and build it.

方法 4:

public static string RenderPartialToString(string controlName, object viewData, object model, System.Web.Routing.RequestContext viewContext)
            {

                ViewDataDictionary vd = new ViewDataDictionary(viewData);
                ViewPage vp = new ViewPage { ViewData = vd };

                vp.ViewData = vd;
                vp.ViewData.Model = model;
                vp.ViewContext = new ViewContext();
                vp.Url = new UrlHelper(viewContext);

                Control control = vp.LoadControl(controlName);

                vp.Controls.Add(control);

                StringBuilder sb = new StringBuilder();

                using (StringWriter sw = new StringWriter(sb))
                {

                    using (HtmlTextWriter tw = new HtmlTextWriter(sw))
                    {

                        vp.RenderControl(tw);

                    }

                }

                return sb.ToString();

            }

(by swilliamsswilliamsAndrew BullockGideonJon)

參考文件

  1. Returning a PartialView with both HTML and JavaScript (CC BY‑SA 3.0/4.0)

#javascript #ajax #asp.net-mvc






相關問題

為什麼我不能在 IE8 (javascript) 上擴展 localStorage? (Why can't I extend localStorage on IE8 (javascript)?)

在 Javascript 中打開外部 sqlite3 數據庫 (Open external sqlite3 database in Javascript)

Javascript:數組中的所有對像都具有相同的屬性 (Javascript: All Objects in Array Have Same Properties)

為什麼我們要在 javascripts 原型中添加函數? (Why do we add functions to javascripts prototype?)

顯示 URL javascript 的最後一部分? (Display the last part of URL javascript?)

Javascript XMLHttpRequest:忽略無效的 SSL 證書 (Javascript XMLHttpRequest: Ignore invalid SSL Certificate)

有沒有辦法測試 console.log 整體 (Is there a way to test for console.log entires)

如何從 javascript 對像中獲取名稱和值到新列表中? (How to get name and values from a javascript object into a new list?)

數據未發布..幫助!html,js,firebase (Data not posting.. Help! html,js,firebase)

使用 Node.js 腳本查看表單數據 (Seeing form data with Node.js script)

使用百分比查找範圍內的值 (find the value within a range using percent)

如何通過 react.js 中的組件傳遞變量或數據? (How to pass varible or data through components in react.js?)







留言討論